using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Security.AccessControl;
using System.IO;

namespace Jalal.Library.Utility
{
    public class FileAccessUtility
    {
        /// <summary>
        /// Private constructor to restrict instance creation
        /// </summary>
        public FileAccessUtility() { }

        /// <summary>
        /// Creates a file in the path location with the provided string content.
        /// The path includes the file name also and is relative to the root of
        /// the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <param name="content">string content of the file</param>
        /// <returns>True if file is successfuly created, false otherwise.</returns>
        public static bool CreateFile(string fullRelativePath, string content)
        {
            bool result = false;
            // If the path is present
            if (!string.IsNullOrEmpty(fullRelativePath))
            {
                // Resolve the relative path
                string fileName = HttpContext.Current.Server.MapPath(fullRelativePath);

                // Create the file
                using (FileStream fileStream = File.Create(fileName))
                {
                    // If the file is writable
                    if (fileStream.CanWrite)
                    {
                        TextWriter writer = new StreamWriter(fileStream);
                        writer.Write(content);
                        writer.Close();
                        fileStream.Close();
                        result = true;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Copy a file in the path location. The path includes the file 
        /// name also and is relative to the root of the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if file is successfuly deleted, false otherwise.</returns>
        public static bool CopyFile(string sourceFullRelativePath, string destinatonFullRelativePath)
        {
            // Resolve the relative path
            string sourceFileName = HttpContext.Current.Server.MapPath(sourceFullRelativePath);
            string destinatonFileName = HttpContext.Current.Server.MapPath(destinatonFullRelativePath);
            File.Copy(sourceFileName, destinatonFileName);
            return true;
        }


        /// <summary>
        /// Deletes a file in the path location. The path includes the file 
        /// name also and is relative to the root of the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if file is successfuly deleted, false otherwise.</returns>
        public static bool DeleteFile(string fullRelativePath)
        {
            // Resolve the relative path
            string fileName = HttpContext.Current.Server.MapPath(fullRelativePath);
            // Deleting the file
            File.Delete(fileName);
            return true;
        }

        /// <summary>
        /// Deletes a file in the path location. The path includes the file 
        /// name also and is relative to the root of the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if file is successfuly deleted, false otherwise.</returns>
        public static bool DeleteFile(string fullRelativePath, bool addSecurity)
        {
            // Resolve the relative path
            string fileName = HttpContext.Current.Server.MapPath(fullRelativePath);
            // Adding file security permission for deletion
            if (addSecurity)
            {
                AddFileSecurity(fileName, System.Security.Principal.WindowsIdentity.GetCurrent().Name,
                  FileSystemRights.Delete, AccessControlType.Allow);
            }
            // Deleting the file
            File.Delete(fileName);
            return true;
        }

        /// <summary>
        /// Delete files in the path location. 
        /// </summary>
        /// <param name="fullRelativePath">The path where to delete the file</param>
        /// <returns>True if file is successfuly deleted, false otherwise.</returns>
        public static bool DeleteFiles(string fullRelativePath, string searchPattern)
        {

            // Resolve the relative path
            string directoryName = HttpContext.Current.Server.MapPath(fullRelativePath);
            DirectoryInfo directory = new DirectoryInfo(directoryName);
            FileInfo[] files = directory.GetFiles(searchPattern);

            foreach (FileInfo file in files)
            {
                string fileName = file.FullName;
                // Adding file security permission for deletion
                AddFileSecurity(fileName, System.Security.Principal.WindowsIdentity.GetCurrent().Name,
                  FileSystemRights.Delete, AccessControlType.Allow);
                // Deleting the file
                File.Delete(fileName);
            }

            return true;
        }
        /// <summary>
        /// Creates a folder in the path location. The path includes the 
        /// file name also and is relative to the root of the website.
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if folder is successfuly created, false otherwise.</returns>
        public static bool CreateFolder(string fullRelativePath)
        {
            // Resolve the relative path
            string folderName = HttpContext.Current.Server.MapPath(fullRelativePath);
            // Creating the directory
            DirectoryInfo directoryInfo = Directory.CreateDirectory(folderName);

            return true;
        }

        /// <summary>
        /// Renames a folder in the path location. The path includes the 
        /// file name also and is relative to the root of the website.
        /// </summary>
        /// <param name="sourceFullRelativePath">The path from where the folder to move</param>
        /// <param name="destinatonFullRelativePath">The path where to move the folder</param>
        /// <returns>True if folder is successfuly moved, false otherwise.</returns>
        public static bool MoveFolder(string sourceFullRelativePath, string destinatonFullRelativePath)
        {
            // Resolve the relative path
            string sourceFolderName = HttpContext.Current.Server.MapPath(sourceFullRelativePath);
            string destinationFolderName = HttpContext.Current.Server.MapPath(destinatonFullRelativePath);
            // Creating the directory
            Directory.Move(sourceFolderName, destinationFolderName);
            return true;
        }

        /// <summary>
        /// Deletes a folder in the path location including child content. The path 
        /// includes the file name also and is relative to the root of the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if folder is successfuly deleted, false otherwise.</returns>
        public static bool DeleteFolder(string fullRelativePath)
        {
            // Resolve the relative path
            string folderName = HttpContext.Current.Server.MapPath(fullRelativePath);
            // If the directory is found
            DirectoryInfo directoryInfo = new DirectoryInfo(folderName);
            if (directoryInfo.Exists)
            {
                // Adding folder security permission for deletion
                AddDirectorySecurity(folderName, System.Security.Principal.WindowsIdentity.GetCurrent().Name,
                  FileSystemRights.Delete, AccessControlType.Allow);
                // Deleting the folder including all child content
                Directory.Delete(folderName, true);
            }
            return true;
        }

        // Adds an ACL entry on the specified file for the specified account.
        public static bool AddFileSecurity(string fileName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            // Get a FileSecurity object that represents the
            // current security settings.
            FileSecurity fSecurity = File.GetAccessControl(fileName);

            // Add the FileSystemAccessRule to the security settings.
            fSecurity.AddAccessRule(new FileSystemAccessRule(account, rights, controlType));

            // Set the new access settings.
            File.SetAccessControl(fileName, fSecurity);

            return true;
        }

        // Removes an ACL entry on the specified file for the specified account.
        public static bool RemoveFileSecurity(string fileName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            // Get a FileSecurity object that represents the
            // current security settings.
            FileSecurity fSecurity = File.GetAccessControl(fileName);

            // Remove the FileSystemAccessRule from the security settings.
            fSecurity.RemoveAccessRule(new FileSystemAccessRule(account, rights, controlType));

            // Set the new access settings.
            File.SetAccessControl(fileName, fSecurity);

            return true;
        }

        // Adds an ACL entry on the specified folder for the specified account.
        public static bool AddDirectorySecurity(string folderName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            // Get a DirectorySecurity object that represents the
            // current security settings.
            DirectorySecurity dSecurity = Directory.GetAccessControl(folderName);

            // Add the FileSystemAccessRule to the security settings.
            dSecurity.AddAccessRule(new FileSystemAccessRule(account, rights, controlType));

            // Set the new access settings.
            Directory.SetAccessControl(folderName, dSecurity);

            return true;
        }

        // Removes an ACL entry on the specified folder for the specified account.
        public static bool RemoveDirectorySecurity(string folderName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            // Get a DirectorySecurity object that represents the
            // current security settings.
            DirectorySecurity dSecurity = Directory.GetAccessControl(folderName);

            // Remove the FileSystemAccessRule from the security settings.
            dSecurity.RemoveAccessRule(new FileSystemAccessRule(account, rights, controlType));

            // Set the new access settings.
            Directory.SetAccessControl(folderName, dSecurity);

            return true;
        }

        public static string UploadFile(HttpPostedFile postedFile, string uploadDirectoryPath, 
            FileTypes fileType)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(HttpContext.Current.Server.MapPath(uploadDirectoryPath));
            if (directoryInfo.Exists)
            {
                if (postedFile != null)
                {
                    if (CompareMimeTypes(postedFile.ContentType, fileType))
                    {
                        string fileName = postedFile.FileName;
                        if (fileName.Contains("\\"))
                        {
                            FileInfo fileInfo = new FileInfo(fileName);
                            fileName = fileInfo.Name;
                        }
                        string suffix = "_" + Guid.NewGuid().ToString().Replace("-", "");
                        fileName = fileName.Insert(fileName.LastIndexOf('.'), suffix);

                        postedFile.SaveAs(HttpContext.Current.Server.MapPath(uploadDirectoryPath + fileName));
                        return uploadDirectoryPath + fileName;
                    }
                    else
                        throw new InvalidDataException("The file format is invalid");
                }
                else
                    throw new ArgumentNullException("No file selected for upload");
            }
            else
                throw new IOException("Upload directory not found");

            return null;
        }

        private static bool CompareMimeTypes(string contentType, FileTypes fileType)
        {
            if (fileType == FileTypes.Zip)
                return (contentType == "application/x-zip-compressed" || contentType == "application/octet-stream");
            else if (fileType == FileTypes.Doc)
                return (contentType == "application/msword");
            else if (fileType == FileTypes.Exe)
                return false;
            else if (fileType == FileTypes.Rar)
                return false;
            else if (fileType == FileTypes.Txt)
                return false;
            else if (fileType == FileTypes.Xls)
                return false;
            else
                return false;
        }

        public enum FileTypes
        {
            Zip = 1,
            Doc ,
            Xls ,
            Rar ,
            Exe ,
            Txt ,
            Flv ,
            Wmv ,
            Avi ,
        }
    }
}
